#include "game_yml.h"
#include "game_log.h"
#include "game_file.h"
#include "game_string.h"
#include <stdio.h>
#include "game_macros.h"

void CGameYML::_trace(){
  //TODO: 测试submodule提交，后续要删掉
}

void CGameYML::trace(const ryml::ConstNodeRef &node){
  __log("\n%s\n","=== CGameYML::trace Start ===");
  __log("id: %d\n",node.id());

  BOOL hasKey = node.has_key() ? TRUE:FALSE;

  __log("has_key: %s\n",hasKey ? "True":"False");

  if(hasKey)
    __log("key: %s\n",node.key().data());
  BOOL isMap = node.is_map() ? TRUE:FALSE;
  __log("is_root %s\n",node.is_root() ? "True":"False");
  __log("is_map %s\n",isMap ? "True":"False");
  __log("is_seq %s\n",node.is_seq() ? "True":"False");
  __log("has_siblings %s\n",node.has_siblings() ? "True":"False");
  __log("has_val %s\n",node.has_val() ? "True":"False");
  __log("num_children is %d\n",node.num_children());
  // node.has_key();

  // node.has_sibling();

  __log("%s\n\n","=== CGameYML::trace End ===");
}

BOOL CGameYML::parse(const char* buf){
  std::string str{buf};
  ryml::parse_in_place(c4::to_substr(str),&_tree);

  return TRUE;
}

BOOL CGameYML::load(const char *filename)
{
  std::string str;

  __get_string_from_file(str, filename);

  _tree = ryml::parse_in_arena(ryml::to_csubstr(str));

  // __log("content is %s\n", str.c_str());
  // __log("size is %d\n", _tree.size());

  // ryml::ConstNodeRef root = _tree.rootref();

  // for(ryml::ConstNodeRef const& child : root.children()){
  //   trace(child);
  // }

  return TRUE;
}

// std::string CGameYML::dump(){
//   std::string str{"aaa"};
//   __log("1 %p\n",&str);
//   __log("2 %p\n",str.c_str());

//   __log("33 %s\n",str.c_str());
//   return str;
// }

size_t CGameYML::getString(char* dest, size_t dest_max, const char* key,const char* _default){
  ryml::NodeRef node;

  if (!getNode(key, node))
  {
    return snprintf(dest,dest_max,"%s",_default);
  }
  size_t s = std::min(node.val().size(), dest_max);
  memcpy(dest,node.val().data(),s);
  return (size_t)node.val().size();
}

std::string CGameYML::getString(const char *key, const char *_default)
{
  // return
  ryml::NodeRef node;

  if (!getNode(key, node))
  {
    return std::string(_default);
  }
  if (node.val_is_null())
  {
    return std::string();
  }
  return std::string(node.val().data(), node.val().size());
}

std::string CGameYML::getString(const char *key, const std::string &_default)
{
  return getString(key, _default.c_str());
}

UINT32 CGameYML::getUINT32(const char *key){
  return getUINT32(key,0);
}

UINT32 CGameYML::getUINT32(const char *key, UINT32 _default)
{
  ryml::NodeRef node;

  if (getNode(key, node))
  {
    return CGameValue::_String2Value<UINT32>(node.val().data(),node.val().size());
  }else return _default;
}

BOOL CGameYML::save(const char* dest){



  do{

    FILE *fp = fopen(dest,"w");

    CC_BREAK_IF_LOG(NULL == fp,"Err When Open YML file:%s\n",dest);

    size_t len = ryml::emit_yaml(_tree, _tree.root_id(), fp);

    fclose(fp);

    CC_BREAK_IF_LOG(0 > len,"Err When Write YML file:%s\n",dest);


    __log("Write YML into file:%s,with %d bytes.\n",dest,len);

    return TRUE;

  }while(true);

  return FALSE;
}

BOOL CGameYML::getNode(ryml::NodeRef &tree ,const char *path, ryml::NodeRef &dest){
  c4::csubstr::split_proxy parts = ryml::to_csubstr(path).split('/');
  ryml::NodeRef &curr = tree;
  for (ryml::csubstr i : parts)
  {
    // 确认当前项是否为数组索引，如下均合法：
    //    /path/.0/name
    //    /path/.1/name
    bool is_seq = __string_startwith(i.data(), ".");

    if (!is_seq && curr.is_map() && curr.has_child(i)) {
      curr = tree[i];
    }
    else if (is_seq && curr.is_seq()) {
      c4::csubstr indexStr = i.sub(1, i.size() - 1);
      int index = atoi(indexStr.data()); // 当前项的下标

      // 寻找下标
      int curIndex = 0;
      for (ryml::NodeRef child : curr.children()) {
        if (curIndex == index) {
          curr = child;
          goto next;
        }
        curIndex++;
      }
      return FALSE; // 无该下标
    }
    else
    {
      return FALSE;
    }
  next:
    is_seq; // note: 编译过
  }
  dest = curr;
  return TRUE;
}

BOOL CGameYML::getNode(const char *path, ryml::NodeRef &dest)
{
  ryml::NodeRef tree = _tree.rootref();
  return CGameYML::getNode(tree,path,dest);
  // c4::csubstr::split_proxy parts = ryml::to_csubstr(path).split('/');
  // // __log("dfdfd %s\n",parts.m_str.data());
  // node = _tree.rootref();
  // for (ryml::csubstr i : parts)
  // {
  //   if (node.is_map() && node.has_child(i))
  //   {
  //     node = node[i];
  //   }
  //   else
  //   {
  //     return FALSE;
  //   }
  // }
  // return TRUE;
  // std::string str(path);




  // // std::str
  // const char *p = strchr(path,'/');

  // while (NULL != p)
  // {
  //   /* code */
  //   __log("%s",p);
  //   p = strchr(p + 1,'/');
  // }


  // return FALSE;
}
